home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Programmer Disk
/
The Programmer Disk (Microforum).iso
/
xpro
/
bc
/
pro18
/
editor.c
< prev
next >
Wrap
Text File
|
1992-05-31
|
29KB
|
1,009 lines
/**********************************************************************\
* *
* editor.c -- this is a primitive graphics mode editor with word-wrap *
* It can be used as a template for a graphics mode editor, but it is *
* not certified bug-free, and anybody thinking of using this code *
* should study it carefully, beta-test it thoroughly, and debug as *
* appropriate. This code is presented here primarily for academic *
* purposes: it is one approach to the problem of how to write a *
* graphics mode text editor. *
* *
* Use this code freely, and send suggestions for optimizations and *
* improvements to Diana Gruber. *
* *
\**********************************************************************/
#include "defs.h"
#define CTRL_Y 25
#define F1 59
#define F2 60
#define F9 67
#define F10 68
#define CHAR_WIDTH 8
int overstrike;
int top_row, bottom_row;
/**********************************************************************\
* *
* can_wrap -- is there enough room to do a word wrap? *
* *
\**********************************************************************/
can_wrap(s1,s2,length)
char *s1, *s2;
int length;
{
if (strlen(s1)+strlen(s2) < (unsigned int)length)
return(TRUE);
else
return(FALSE);
}
/**********************************************************************\
* *
* clear_string -- clear all or part of a row of chars *
* *
\**********************************************************************/
void clear_string(x,y,len,maxx)
int x, y, len, maxx;
{
int x1, y0;
int color;
if (len == 0) return;
y0 = y - ptsize;
x1 = x + len * CHAR_WIDTH - 1;
if (x1 > maxx) x1 = maxx;
color = fg_getcolor();
fg_setcolor(background);
fg_rect(x,x1,y0,y);
fg_setcolor(color);
}
/**********************************************************************\
* *
* editor -- edit nrows lines of text *
* *
\**********************************************************************/
editor(array,minx,maxx,miny,maxy,nrows,array_len)
char *array;
int minx, miny, maxx, maxy, nrows;
int *array_len;
{
register int i, n;
int b, l;
int x, y;
int iy;
unsigned char key, aux;
static char char_string[] = {0,0};
int maxcol;
int row;
char *tempstring;
char *string[101];
int col[101];
int end[101];
int color;
int visible_rows;
color = fg_getcolor();
fg_setpage(visual);
overstrike = FALSE;
iy = miny + ptsize;
/* determine the string size */
maxcol = (maxx+1 - minx) / CHAR_WIDTH;
/* allocate space for the strings and initialize all elements to 0 */
for (n = 0; n < nrows; n++)
{
if ((string[n] = calloc(maxcol+3,sizeof(char))) == '\0')
return(ERR);
col[n] = 0;
end[n] = 0;
}
tempstring = calloc(maxcol+2,sizeof(char));
/* display whatever is in the array now */
l = 0;
x = minx;
y = iy;
top_row = 0;
bottom_row = ((maxy - miny + 1) / (ptsize+1));
if (bottom_row > nrows) bottom_row = nrows;
/* recalc maxy based on ptsize, for scrolling */
maxy = iy + 1 + (bottom_row-1) * (ptsize + 1);
/* recalc nrows because they don't seem to come out right? */
nrows++;
for (row = top_row; row < bottom_row; row++)
{
put_string(&array[l],x,y);
strcpy(string[row],&array[l]); /* copy it to the temp string */
unblank(string[row]);
l += strlen(&array[l]) + 1;
col[row] = strlen(string[row]);
y += ptsize + 1;
}
/* if there any rows beyond the bottom row */
for (row = bottom_row; row<nrows; row++)
{
strcpy(string[row],&array[l]);
l += strlen(&array[l]) + 1;
unblank(string[row]);
col[row] = strlen(string[row]);
}
flushkey();
row = 0; /* starting position */
col[row] = 0;
x = get_x(minx,col[row]);
y = iy;
put_editor_cursor(x,y);
visible_rows = bottom_row - top_row;
while (TRUE)
{
fg_getkey(&key,&aux);
/* return */
if (key == CR)
{
unblank(string[row]);
remove_editor_cursor(x,y);
if (row < bottom_row - 1)
{
n = end_paragraph(row,string);
if (n < bottom_row - 1)
{
for (i = n; i > row; i--)
{
strcpy(string[i+1],string[i]);
y = get_y(iy,i+1);
clear_string(minx,y,maxcol,maxx);
put_string(string[i+1],minx,y);
}
strcpy(string[row+1],&string[row][col[row]]);
string[row][col[row]] = '\0';
x = get_x(minx,col[row]);
y = get_y(iy,row);
clear_string(x,y,maxcol,maxx);
y = get_y(iy,row+1);
clear_string(minx,y,maxcol,maxx);
put_string(string[row+1],minx,y);
}
row++;
}
else if (bottom_row < nrows - 1)
{
fg_setcolor(background);
fg_scroll(minx,maxx,(iy+1),maxy,-(ptsize+1),1);
fg_setcolor(color);
bottom_row++;
top_row++;
row++;
y = get_y(iy,bottom_row-1);
put_string(string[bottom_row-1],minx,y);
}
else
row = top_row;
col[row] = 0;
x = get_x(minx,col[row]);
y = get_y(iy,row);
put_editor_cursor(x,y);
}
/* F1 -- help screen */
else if (aux == F1)
{
remove_editor_cursor(x,y);
help_screen();
fg_setcolor(15);
put_editor_cursor(x,y);
}
/* back space */
else if (key == BS && col[row] > 0)
{
remove_editor_cursor(x,y);
col[row]--;
string[row][col[row]] = '\0'; /* remove a character */
strcpy(tempstring,string[row]);
strcat(tempstring,&string[row][col[row]+1]);
strcpy(string[row],tempstring);
x = get_x(minx,col[row]);
clear_string(x,y,maxcol,maxx);
put_string(&string[row][col[row]],x,y);
put_editor_cursor(x,y);
}
/* delete */
else if (aux == DELETE)
{
if (string[row][col[row]] == '\0' && row < bottom_row-1)
/* delete at end of line */
{
end[row] = strlen(string[row]);
end[row+1] = strlen(string[row+1]);
b = first_blank(string[row+1]);
if (end[row] + b <= maxcol)
{
remove_editor_cursor(x,y);
/* see if you can wrap more than one word */
while (end[row]+b <= maxcol && b < end[row+1])
{
n = b;
b += first_blank(&string[row+1][b+1]) + 1;
}
if (end[row]+b > maxcol) b = n;
if (string[row+1][b] == '\0') /* wrap whole line */
{
strcat(string[row],string[row+1]); /* move all lines up */
for (i = row+1; i < bottom_row; i++)
{
strcpy(string[i],string[i+1]);
y = get_y(iy,i);
clear_string(minx,y,maxcol,maxx);
put_string(string[i],minx,y);
}
for (i = bottom_row; i < nrows-1; i++)
{
strcpy(string[i],string[i+1]);
}
string[nrows-1][0] = '\0';
}
else /* wrap one word of several on next line */
{
string[row+1][b] = '\0';
strcat(string[row],string[row+1]);
strcpy(tempstring,&string[row+1][b+1]);
strcpy(string[row+1],tempstring);
y = get_y(iy,row+1);
clear_string(minx,y,maxcol,maxx);
put_string(string[row+1],minx,y);
}
x = get_x(minx,col[row]);
y = get_y(iy,row);
put_string(&string[row][col[row]],x,y);
put_editor_cursor(x,y);
}
continue;
}
else if (string[row][col[row]] != '\0')
{
string[row][col[row]] = '\0'; /* remove a character */
strcpy(tempstring,string[row]);
strcat(tempstring,&string[row][col[row]+1]);
strcpy(string[row],tempstring);
clear_string(x,y,maxcol,maxx);
put_string(&string[row][col[row]],x,y);
}
}
/* line delete -- ctrl y */
else if (key == CTRL_Y)
{
col[row] = 0;
string[row][col[row]] = '\0';
remove_editor_cursor(x,y);
x = minx;
clear_string(x,y,maxcol,maxx);
put_editor_cursor(x,y);
}
/* left arrow */
else if (aux == LEFT_ARROW)
{
if (col[row] > 0)
{
remove_editor_cursor(x,y);
col[row]--;
x = get_x(minx,col[row]);
put_editor_cursor(x,y);
}
else if (row > 0)
{
remove_editor_cursor(x,y);
row--;
end[row] = strlen(string[row]);
col[row] = MIN(end[row],maxcol-1);
x = get_x(minx,col[row]);
y = get_y(iy,row);
put_editor_cursor(x,y);
}
}
/* right arrow */
else if (aux == RIGHT_ARROW)
{
if (col[row] < maxcol-1)
{
if (string[row][col[row]] == '\0')
{
string[row][col[row]] = 32;
string[row][col[row]+1] = '\0';
}
remove_editor_cursor(x,y);
col[row]++;
x = get_x(minx,col[row]);
put_editor_cursor(x,y);
}
else if (row < bottom_row-1)
{
remove_editor_cursor(x,y);
row++;
col[row] = 0;
x = get_x(minx,col[row]);
y = get_y(iy,row);
put_editor_cursor(x,y);
}
}
/* up arrow */
else if (aux == UP_ARROW)
{
if (row > top_row)
{
unblank(string[row]);
remove_editor_cursor(x,y);
row--;
end[row] = strlen(string[row]);
col[row] = MIN(end[row],col[row+1]);
x = get_x(minx,col[row]);
y = get_y(iy,row);
put_editor_cursor(x,y);
}
else if (top_row > 0)
{
unblank(string[row]);
remove_editor_cursor(x,y);
end[row] = strlen(string[row]);
col[row] = 0;
bottom_row--;
top_row--;
row--;
fg_setcolor(background);
fg_scroll(minx,maxx,miny-1,maxy-ptsize-3,ptsize+1,1);
fg_setcolor(color);
x = get_x(minx,col[row]);
y = get_y(iy,row);
put_string(string[row],minx,y);
put_editor_cursor(x,y);
}
}
/* down arrow */
else if (aux == DOWN_ARROW)
{
if (row < bottom_row-1)
{
unblank(string[row]);
remove_editor_cursor(x,y);
row++;
end[row] = strlen(string[row]);
col[row] = MIN(end[row],col[row-1]);
x = get_x(minx,col[row]);
y = get_y(iy,row);
put_editor_cursor(x,y);
}
else if (bottom_row < nrows-1)
{
unblank(string[row]);
remove_editor_cursor(x,y);
bottom_row++;
top_row++;
row++;
end[row] = strlen(string[row]);
col[row] = MIN(end[row],col[row-1]);
fg_setcolor(background);
fg_scroll(minx,maxx,iy+1,maxy,-(ptsize+1),1);
fg_setcolor(color);
x = get_x(minx,col[row]);
y = get_y(iy,row);
put_string(string[row],minx,y);
put_editor_cursor(x,y);
}
}
/* PgUp */
else if (aux == PAGE_UP && row > 0)
{
if (top_row > visible_rows)
{
top_row -= visible_rows;
bottom_row -= visible_rows;
}
else
{
top_row = 0;
bottom_row = visible_rows;
}
fg_setcolor(background);
fg_rect(minx,maxx,miny,maxy);
fg_setcolor(color);
for (row = top_row; row < bottom_row; row++)
{
y = get_y(iy,row);
put_string(string[row],minx,y);
}
row = top_row;
end[row] = strlen(string[row]);
col[row] = 0;
x = get_x(minx,col[row]);
y = get_y(iy,row);
put_editor_cursor(x,y);
}
/* PgDn */
else if (aux == PAGE_DOWN)
{
if (bottom_row < nrows-visible_rows)
{
top_row += visible_rows;
bottom_row += visible_rows;
}
else
{
top_row = nrows - visible_rows - 1;
bottom_row = nrows - 1;
}
fg_setcolor(background);
fg_rect(minx,maxx,miny,maxy);
fg_setcolor(color);
for (row = top_row; row < bottom_row; row++)
{
y = get_y(iy,row);
put_string(string[row],minx,y);
}
row = top_row;
end[row] = strlen(string[row]);
col[row] = 0;
x = get_x(minx,col[row]);
y = get_y(iy,row);
put_editor_cursor(x,y);
}
/* home */
else if (aux == HOME)
{
remove_editor_cursor(x,y);
col[row] = 0;
x = get_x(minx,col[row]);
y = get_y(iy,row);
put_editor_cursor(x,y);
}
/* end */
else if (aux == END)
{
remove_editor_cursor(x,y);
unblank(string[row]);
end[row] = strlen(string[row]);
col[row] = MIN(end[row],maxcol-1);
x = get_x(minx,col[row]);
y = get_y(iy,row);
put_editor_cursor(x,y);
}
/* insert toggles insert mode */
else if (aux == INSERT)
{
overstrike = !overstrike;
put_editor_cursor(x,y);
}
/* esc or F10 to return */
else if (aux == F10 || key == ESC)
break;
/* printable character -- insert mode */
if ((is_char(key) || key == SPACEBAR) && !overstrike)
{
l = 0;
remove_editor_cursor(x,y);
strcpy(tempstring,&string[row][col[row]]);
string[row][col[row]] = key;
string[row][col[row]+1] = '\0';
strcat(string[row],tempstring);
end[row] = strlen(string[row]);
/* row too long, must wrap */
if (end[row] > maxcol || col[row] == maxcol-1)
{
if (row == bottom_row-1 && bottom_row < nrows-1)
{
fg_setcolor(background);
fg_scroll(minx,maxx,iy+1,maxy,-(ptsize+1),1);
fg_setcolor(color);
bottom_row++;
top_row++;
y = get_y(iy,row+1);
put_string(string[row+1],minx,y);
}
if (row < bottom_row-1)
{
b = last_blank(string[row]) + 1;
if (can_wrap(&string[row][b],string[row+1],maxcol))
{
l = b - col[row];
word_wrap(&string[row][b],string[row+1]);
string[row][b] = '\0';
unblank(string[row]);
unblank(string[row+1]);
/* redraw the second row of text */
y = get_y(iy,row+1);
clear_string(minx,y,maxcol,maxx);
put_string(string[row+1],minx,y);
/* recalc cursor position */
if (col[row] >= b) /* cursor is in word that gets wrapped */
{
/* erase last word of row */
x = get_x(minx,b);
y = get_y(iy,row);
clear_string(x,y,maxcol,maxx);
row++;
col[row] = col[row-1] - b;
unblank(string[row]);
}
else /* cursor stays on current line */
{
x = get_x(minx,col[row]);
y = get_y(iy,row);
clear_string(x,y,maxcol,maxx);
put_string(&string[row][col[row]],x,y);
}
}
else /* can't wrap: shorten string */
{
string[row][maxcol] = '\0';
y = get_y(iy,row);
clear_string(x,y,maxcol,maxx);
put_string(&string[row][col[row]],x,y);
}
if (col[row] < maxcol-1)
col[row]++;
else if (row < bottom_row)
{
row++;
col[row] = 0;
unblank(string[row]);
}
x = get_x(minx,col[row]);
y = get_y(iy,row);
put_editor_cursor(x,y);
}
else /* row = bottom_row-1 */
{
string[row][maxcol] = '\0';
clear_string(x,y,maxcol,maxx);
y = get_y(iy,row);
put_string(&string[row][col[row]],x,y);
x = get_x(minx,col[row]);
y = get_y(iy,row);
put_editor_cursor(x,y);
}
}
else /* wrapping not necessary */
{
x = get_x(minx,col[row]);
y = get_y(iy,row);
clear_string(x,y,maxcol,maxx);
put_string(&string[row][col[row]],x,y);
end[row] = strlen(string[row]);
if (col[row] <= end[row]+1 && col[row] < maxcol-1)
col[row]++;
else if (row < bottom_row-1)
{
row++;
col[row] = l;
}
else
{
x = get_x(minx,col[row]);
y = get_y(iy,row);
string[row][maxcol] = '\0';
clear_string(x,y,maxcol,maxx);
put_string(&string[row][col[row]],x,y);
}
x = get_x(minx,col[row]);
y = get_y(iy,row);
put_editor_cursor(x,y);
}
}
/* printable character -- overstrike mode */
else if ((is_char(key) || key == SPACEBAR) && overstrike)
{
remove_editor_cursor(x,y);
string[row][col[row]] = key;
char_string[0] = key;
clear_string(x,y,1,maxx);
put_string(char_string,x,y);
if (col[row] < maxcol-1)
col[row]++;
/* trying to write a character past the end of a row, must wrap */
else if (row < bottom_row-1)
{
b = last_blank(string[row])+1;
l = strlen(&string[row][b]);
unblank(string[row+1]);
if (can_wrap(&string[row][b],string[row+1],maxcol))
{
word_wrap(&string[row][b],string[row+1]);
string[row][b] = '\0';
/* redraw the two rows of text */
y = get_y(iy,row);
clear_string(minx,y,maxcol,maxx);
put_string(string[row],minx,y);
row++;
unblank(string[row]);
y = get_y(iy,row);
clear_string(minx,y,maxcol,maxx);
put_string(string[row],minx,y);
col[row] = l;
}
else
{
row++;
col[row] = 0;
unblank(string[row]);
}
}
x = get_x(minx,col[row]);
y = get_y(iy,row);
put_editor_cursor(x,y);
}
}
/* end while */
l = 0; /* put all the strings in one array */
for (n = 0; n < nrows; n++) /* separated by '\0's */
{
strcpy(&array[l],string[n]);
l += strlen(string[n]) + 1;
free (string[n]); /* free the temporary arrays */
array[l] = 0;
l++;
}
*array_len = l;
free(tempstring);
return(OK);
}
/**********************************************************************\
* *
* end_paragraph -- find the first blank line after a line of text *
* *
\**********************************************************************/
end_paragraph(row,string)
char *string[60];
int row;
{
register int n;
for (n = row+1; n < 60; n++)
{
unblank(string[n]);
if (string[n][0] == '\0')
break;
}
n--;
return(n);
}
/**********************************************************************\
* *
* first_blank -- find the first blank space before the end of a string *
* *
\**********************************************************************/
first_blank(s)
char *s;
{
register int i;
int nchar;
nchar = strlen(s);
i = 0;
while (i <= nchar && is_char(s[i]))
i++;
/* return value of blank */
return(i);
}
/**********************************************************************\
* *
* get_x -- calculate the x position based on row and column *
* *
\**********************************************************************/
get_x(x,col)
int x, col;
{
return(x + col * CHAR_WIDTH);
}
/**********************************************************************\
* *
* get_y -- calculate the y position based on row and column *
* *
\**********************************************************************/
get_y(y,row)
int y, row;
{
return(y + (row-top_row) * (ptsize+1));
}
/**********************************************************************\
* *
* help_screen -- display keystroke help *
* *
\**********************************************************************/
void help_screen()
{
register int i;
unsigned char key, aux;
static char string[13][50] = {
" Arrows: move the cursor around",
" Del: delete a letter",
" Ctrl-Y: delete the whole line",
" Home: go to beginning of line",
" End: go to end of line",
" PgUp: go up one screen",
" PgDn: go down one screen",
" Enter: go to the next line",
" Ins: insert or overstrike" ,
" Esc: done editing" ,
" "
" press any key to exit help"
};
static int line [] = {46,58,70,82,94,106,118,130,142,154,166,182};
fg_save(10,309,25,189);
background = 2;
fg_setcolor(2);
fg_rect(10,309,25,189);
fg_setcolor(15);
fg_box(11,308,26,188);
for (i = 0; i < 12; i++)
{
put_string(string[i],14,line[i]);
}
fg_getkey(&key,&aux);
fg_restore(10,309,25,189);
background = 0;
}
/**********************************************************************\
* *
* is_char -- is it a legitimate character that we can display? *
* *
\**********************************************************************/
is_char(c)
char c;
{
if (c > 32 && c <= 126)
return(TRUE);
else
return(FALSE);
}
/**********************************************************************\
* *
* last_blank -- find the last blank space before the end of a string *
* *
\**********************************************************************/
last_blank(s)
char *s;
{
register int i;
/* find the end of the string */
for (i = 0; s[i]; i++)
;
/* count backwards, finding the blank */
while (i > 0 && is_char(s[i-1]))
i--;
i--; /* next character back must be non-alpha */
/* return value of blank */
return(i);
}
/**********************************************************************\
* *
* put_editor_cursor -- put a cursor under where the next char goes *
* *
\**********************************************************************/
void put_editor_cursor(x,y)
int x, y;
{
int color;
color = fg_getcolor();
if (mode06 || mode11)
fg_setcolor(1);
else if (overstrike)
fg_setcolor(2);
else
fg_setcolor(14);
fg_move(x,y+1);
fg_draw(x+8,y+1);
fg_setcolor(color);
}
/**********************************************************************\
* *
* remove_editor_cursor -- delete the cursor from its current position *
* *
\**********************************************************************/
void remove_editor_cursor(x,y)
int x, y;
{
int color;
color = fg_getcolor();
fg_setcolor(background);
fg_move(x,y+1);
fg_draw(x+8,y+1);
fg_setcolor(color);
}
/**********************************************************************\
* *
* unblank -- remove trailing blanks and other garbage from a string *
* *
\**********************************************************************/
void unblank(s)
char *s;
{
register int i;
/* find the end of the string */
for (i = 0; s[i]; i++)
;
/* count back trailing spaces */
while (i > 0 && !is_char(s[i-1]))
i--;
/* set new end of string */
s[i] = '\0';
}
/**********************************************************************\
* *
* word_wrap -- take the last word of one string, put at beginning of *
* next string. *
* *
\**********************************************************************/
void word_wrap(s1,s2)
char *s1, *s2;
{
char tempstring[60];
strcpy(tempstring,s1);
strcat(tempstring," ");
strcat(tempstring,s2);
strcpy(s2,tempstring);
}